//因为ajax步骤比较多,所以我们对其进行封装

//1.确定一下ajax使用方式是什么

// ajax({
//     url: "http://chst.vip/weather/getWeather", //请求地址
//     method:'get',
//     data:{
//         key:"value"
//     }
// })



//2.定义ajax函数
//封装的含义?1.使用方便 2.可复用性强
function ajax(options) {
    // console.log(options);
    //1.如何变得方便? 用户只传了url,我们我们就需要默认的给method变成get请求
    //设定一个对象,和用户传入的对象进行混合,以用户传入的属性为主
    let defaultOption = {
        url: "", //请求地址
        method: "get",// 请求方式
        data: {},//传递的参数
        async: true,//默认开启异步
        responseType: "json",  //响应数据的类型json || text
        success(res) {//请求成功的回调
            console.log(res);
        },
        error(err) { //失败的回调
            console.log(err);
        }
    }
    //原生写法
    // for (k in options) {
    //     defaultOption[k] = options[k]
    // }

    //es6写法
    defaultOption = Object.assign({}, defaultOption, options) //将传入的options合并到defaultOption里面

    // console.log(defaultOption);

    //解构defaultOption中的属性

    let { url, method, data, async, success, error, responseType } = defaultOption;

    //考虑用于传递method可能大写比如GET POST,我们统一处理成小写

    method = method.toLowerCase();

    //处理data参数
    //把{key:"all",city:"南京"}处理成 "key=all&city=南京"这种格式
    let params = "";
    for (k in data) {
        params += `${k}=${data[k]}&`
    }

    params = params.substr(0, params.length - 1)
    // console.log(params);

    //编写核心逻辑

    //1.实例化xhr

    let xhr;

    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest()
    } else {
        xhr = new ActiveXObject('microsoft.XMLHTTP')
    }

    //设置请求头,post请求的时候,使用MIME类型为x-www-form-urlencoded
    // console.log(xhr.setRequestHeader);
    //get请求的时候 send(null),url需要拼接query参数
    //不是get请求的时候,send(key=val)中需要传入参数,url地址后面不需要拼接参数
    xhr.open(method, url + (method === 'get' ? "?" + params : ""), async)

    if (method === "post") xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded")

    xhr.send(method === "get" ? null : params)
    xhr.onerror = function (err) {
        //ajax请求出错了,回调错误处理函数
        //console.log(err);
        error(err)
    }

    //处理同步请求的数据返回
    if (!async) { //表示同步,async默认是true
        if (xhr.readyState === 4 && xhr.status === 200) {
            let res;
            //直接把结果返回给ajax
            if (responseType === "json") {
                res = JSON.parse(xhr.responseText)

            } else if (responseType === "text") {
                res = xhr.responseText
            }

            return res;//直接返回给ajax函数
        }
    }

    //异步ajax处理
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            let res;
            if (responseType === "json") {
                //将数据处理成对象,并且返回
                res = JSON.parse(xhr.responseText)
            } else if (responseType === "text") {
                res = xhr.responseText
            }
            success(res)
        }
    }
}


function core(defaultOption, resolve, reject) {
    // 解构赋值获取对象里的数据
    let { data, url, method, async, headers, success, error, responseType } =
      defaultOption;
  
    // 创建ajax
    let xhr;
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest();
    } else {
      xhr = new ActiveXObject("microsoft.XMLHTTP");
    }
  
    // 根据不同情况转换成各类格式的data参数
    let params = "";
  
    // data数据转换
    if (JSON.stringify(data) !== "{}") {
      for (let k in data) {
        params += k + "=" + data[k] + "&";
      }
      params = params.substr(0, params.length - 1);
    }
  
    // 建立请求
    xhr.open(
      method,
      url + (!!params && method === "get" ? "?" + params : ""),
      async
    );
  
    // header判断
    if (typeof headers === "object") {
      if (JSON.stringify(headers) === "{}") {
        error("请求头传递的是一个空对象", xhr);
      }
    } else {
      if (async) reject("headers expected object but got a " + typeof headers);
      throw new Error("headers expected object but got a " + typeof headers);
    }
  
    // post /json 传参时的方式
    for (let h in headers) {
      if (
        h.toLowerCase() == "content-type" &&
        method === "post" &&
        JSON.stringify(data) !== "{}"
      ) {
        if (headers[h].toLowerCase() === "application/json") {
          params = JSON.stringify(data);
        }
      }
      // 设置请求头
      xhr.setRequestHeader(h, headers[h]);
    }
  
    // 发送请求
    xhr.send(method !== "post" ? null : params);
  
    // 如果是同步,这里就直接返回结果
    if (!async) {
      return responseType === "json"
        ? JSON.parse(xhr.responseText)
        : xhr.responseText;
    }
  
    // 响应
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {
          let res = xhr.responseText;
          switch (responseType.toLowerCase()) {
            case "text":
              success(res);
              resolve(res);
              break;
            case "json":
              success(JSON.parse(res));
              resolve(JSON.parse(res));
              break;
            default:
              success(res);
              resolve(res);
          }
        }
      }
    };
  
    xhr.onerror = function (e) {
      error(e, xhr);
      reject(e, xhr);
    };
  }
  
  function ajax(options) {
    // 判断是否传入的是一个对象
    let isObject = Object.prototype.toString
      .call(options)
      .replace(/[\[\]]/g, "")
      .substr(7)
      .toLowerCase();
  
    if (isObject !== "object") {
      throw new Error(
        "传入的必须是一个对象, the param expected a object,but got a " + isObject
      );
    }
  
    // 设置默认参数
    let defaultOption = {
      url: "",
      method: "get",
      responseType: "json",
      data: {},
      async: true,
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
      success: function (res) {},
      error: function (e) {},
    };
  
    // 传入对象和默认对象混合
    for (let k in options) {
      defaultOption[k] = options[k];
    }
  
    // 同步异步判断
    if (defaultOption.async === false) {
      return core(defaultOption);
    } else {
      return new Promise((resolve, reject) => {
        core(defaultOption, resolve, reject);
      });
    }
  }
  
